package chagine.core.lock.redis.util;


import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 浙江贯通技术股份有限公司
 *
 * @author 张正伟
 * @create 2019-07-02 10:44
 */
@Component
public class SeeingLockRedisUtilFactory {

    private Map<Integer, SeeingLockRedisUtil> redisUtilMap = new ConcurrentHashMap<>(20);

    private static final Object LOCK = new Object();

    private static volatile SeeingLockRedisUtilFactory ru;

    private final RedisConnectionFactory redisConnectionFactory
            ;

    public SeeingLockRedisUtilFactory(RedisConnectionFactory redisConnectionFactory) {
        if (ru != null) {
            throw new UnsupportedOperationException("单例不允许多次创建");
        }
        this.redisConnectionFactory = redisConnectionFactory;
        SeeingLockRedisUtilFactory.ru = this;
    }

    @Deprecated
    public static SeeingLockRedisUtilFactory getInstance() {
        return ru;
    }

    public SeeingLockRedisUtil getSeeingLockRedisUtil() {
        // 默认的使用 -1
        return getSeeingLockRedisUtil(-1);
    }

    public SeeingLockRedisUtil getSeeingLockRedisUtil(int dbIndex) {

        if (!redisUtilMap.containsKey(dbIndex)) {
            synchronized (LOCK) {
                if (!redisUtilMap.containsKey(dbIndex)) {
                    // 初始化数据
                    RedisTemplate<String, LockInfo> redisTemplate;
                    RedisTemplate<String, Long> longRedisTemplate;
                    redisTemplate = redisTemplate(redisConnectionFactory);
                    longRedisTemplate = longRedisTemplate(redisConnectionFactory);
                    SeeingLockRedisUtil redisUtil = new SeeingLockRedisUtil(redisTemplate, longRedisTemplate);
                    // 放入缓存
                    redisUtilMap.putIfAbsent(dbIndex, redisUtil);
                }
            }
        }

        return redisUtilMap.get(dbIndex);
    }

    private RedisTemplate<String, LockInfo> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, LockInfo> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new Jackson2JsonRedisSerializer<>(LockInfo.class));
        template.afterPropertiesSet();
        return template;
    }

    private RedisTemplate<String, Long> longRedisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Long> longRedisTemplate = new RedisTemplate<>();
        longRedisTemplate.setConnectionFactory(factory);
        longRedisTemplate.setKeySerializer(new StringRedisSerializer());
        longRedisTemplate.setValueSerializer(new GenericToStringSerializer<>(Long.class));
        longRedisTemplate.afterPropertiesSet();
        return longRedisTemplate;
    }
}
